package annoaop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

import java.util.Arrays;

@Aspect//切面类
@Component//ioc容器
public class LogAspect {
    //设置切入点和通知类型
    //通知类型：前置@Before() 返回@AfterReturning()
    //        异常@AfterThrowing() 后置@After() 环绕@Around()

    //切入点表达式配置切入点  . *表示所有

    //前置通知 方法执行前执行
    @Before(value = "execution(public int annoaop.CalculatorImpl.add(..))")
    public void beforeMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        System.out.println("Logger -> 前置通知,方法名称：" + methodName + ",参数：" + Arrays.toString(args));
    }

    //后置通知 最终结束后执行
    @After(value = "pointCut()")
    public void afterMethod(JoinPoint joinPoint) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Logger -> 后置通知,方法名称：" + methodName);
    }

    //返回通知 成功后执行
    //返回通知可获得目标通知返回值
    @AfterReturning(value = "pointCut()", returning = "result1")
    public void afterReturningMethod(JoinPoint joinPoint, Object result1) {
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Logger -> 返回通知,方法名称：" + methodName + ",目标方法返回值：" + result1);
    }

    //异常通知 异常结束后执行
    @AfterThrowing(value = "pointCut()",throwing = "ex")
    public void afterThrowingMethod(JoinPoint joinPoint,Throwable ex){
        String methodName = joinPoint.getSignature().getName();
        System.out.println("Logger -> 异常通知,方法名称：" +methodName+",异常信息："+ex);
    }

    //环绕通知 使用try...catch...finally结构围绕**整个**被代理的目标方法，包括上面四种通知对应的所有位置
    @Around(value = "pointCut()")
    public Object aroundMethod(ProceedingJoinPoint joinPoint){
        String methodName = joinPoint.getSignature().getName();
        Object[] args = joinPoint.getArgs();
        String argString = Arrays.toString(args);
        System.out.println("Logger -> 环绕通知,方法名称：" +methodName+"");
        Object result = null;
        try{
            System.out.println("环绕通知==目标方法之前执行");
            //调用目标方法
            result = joinPoint.proceed();
            System.out.println("环绕通知==目标方法返回值之后执行");
        }catch (Throwable throwable){
            throwable.printStackTrace();
            System.out.println("环绕通知==目标方法出现异常执行");
        }finally {
            System.out.println("环绕通知==目标方法执行完毕执行");
        }
        return result;
    }

    @Pointcut(value = "execution(* annoaop.CalculatorImpl.*(..))")
    public void pointCut(){

    }

}
